<?php
/**
 * Created by PhpStorm.
 * User: 牛赞赞
 * Date: 2021/1/11
 * Time: 14:37
 */

namespace App\Task;

use App\Game\Conf\GameProgress;
use App\Game\Timer\GameTimer;
use App\Model\GameTaskDayComplete;
use App\Model\GameTaskDayList;
use App\Model\GameTaskGrowComplete;
use App\Model\GameTaskGrowList;
use App\Model\User;
use Hyperf\DbConnection\Db;
use App\Game\Core\Packet;
use App\Game\Conf\MainCmd;
use App\Game\Conf\SubCmd;
use App\Game\Core\DdzPoker;
use Psr\Container\ContainerInterface;
use Swoole\WebSocket\Server as WebSocketServer;

class GameTimerTask
{
    /**
     * @var ContainerInterface
     */
    private $container;


    public static $CHANGE_CARD_TIMER = 1;   //换牌定时器
    public static $CHOOSE_COLOR_TIMER = 2;  //定缺定时器
    public static $OUT_CARD_TIMER = 3;      //出牌定时器
    public static $CHECK_HPK_TIMER = 4;     //检查胡碰杠定时器


    public function __construct(ContainerInterface $container)
    {
        $this->container = $container;
    }


//    public static function run($timer, $room_no, $wait_time)
//    {
//
//        $wait_time *= 1000;
//        switch ($timer) {
//            case GameTimer::$CHANGE_CARD_TIMER :
//                $name = 'change_card';
//                break;
//            case GameTimer::$CHOOSE_COLOR_TIMER:
//                $name = 'choose_color';
//                break;
//            case GameTimer::$OUT_CARD_TIMER:
//                $name = 'out_card';
//                break;
//            case GameTimer::$CHECK_HPK_TIMER:
//                $name = 'check_hpg';
//                break;
//        }
//        $time = time();
//        $timerId = \Swoole\Timer::after($wait_time, function () use ($timer, $room_no, $name, $time) {
//            $lastTimer = getLastTimer($room_no);
//            dd('lastTimer', $lastTimer);
//            dd('on ' . $name . ' timer', $time);
//            if ($lastTimer && ($lastTimer['time'] != date('i:s', $time))) {
//                dd($name . ' timer die ', $time);
//                return;
//            }
//            switch ($timer) {
//                case GameTimer::$CHANGE_CARD_TIMER :
//                    ddTitle('change_card_timer room_no:' . $room_no . ' | time:' . date('Y-m-d H:i:s', time()));
//                    GameTimer::do_change_card($room_no);
//                    break;
//                case GameTimer::$CHOOSE_COLOR_TIMER:
//                    ddTitle('choose_color_timer :' . $room_no . ' | time:' . date('Y-m-d H:i:s', time()));
//                    GameTimer::do_choose_color($room_no);
//                    break;
//                case GameTimer::$OUT_CARD_TIMER:
//                    ddTitle('out_card_timer :' . $room_no . ' | time:' . date('Y-m-d H:i:s', time()));
//                    GameTimer::do_out_card($room_no);
//                    break;
//                case GameTimer::$CHECK_HPK_TIMER:
//                    ddTitle('check_hpk_timer :' . $room_no . ' | time:' . date('Y-m-d H:i:s', time()));
//                    GameTimer::do_check_hpk($room_no);
//                    break;
//            }
//        });
//
//        ddTitle('add ' . $name . ' timer  id:' . $timerId . ' wait_time: ' . $wait_time . '  ' . date
//            ('i:s', time()));
//        //添加定时器缓存
//        addTimer($room_no, $timerId, $name, $time);
//    }


    function clean($room_no)
    {
        cleanTimer($room_no);
    }

    //换牌
    public function do_change_card($room_no)
    {
        ddTitle('start do_change_card:' . $room_no);
        //检查游戏进度，如果不是当前进度，则不执行当前调用流程
        if (!checkGameProgress($room_no, GameProgress::GAME_CHANGE_CARD)) {
            ddTitle('exit by game progress, current progress: ' . getGameProgress($room_no) . ' need progress:' . GameProgress::GAME_CHANGE_CARD);
            return;
        }
        //添加操作计数器，防止重复操作
        addOperCounter($room_no);
        //检查计数器，如果计数器被增加了，表示操作被执行过，则不再重复执行该调用流程
        if (!checkCounter($room_no)) {
            ddTitle('exit by opercounter, current counter: ' . getCounter($room_no));
            return;
        }
        $game_conf = config('game');
        $user_conf = config('user');
        $serv = server();
        $user_changes = getRoomChangeCards($room_no);
        $room_data = getRoomData($room_no);
        $user_chairs = getRoomChairs($room_no);

        // 1.判断已操作换牌用户数，没满员则由系统自动给未操作玩家执行换牌
//        dd('user_changes befor', $user_changes);
        $notOperUserArr = [];
        if (count($user_changes) < 4) {
            $changeKyes = array_keys($user_changes);
            foreach ($user_chairs as $k => $v) {
                if (!in_array($v, $changeKyes)) {
                    $notOperUserArr[] = ['account' => $k, 'chair_id' => $v];
                }
            }
        }
//        dd('notOperUserArr', $notOperUserArr);
        if (!empty($notOperUserArr)) {
//            ddNode('auto change card, players:' . count($notOperUserArr));
            foreach ($notOperUserArr as $v) {
                $user_data = json_decode($room_data[$v['account']], true);
                $user_changes[$v['chair_id']] = randChangeCard($user_data['card']);
            }
        }
//        dd('user_changes after', $user_changes);
        $changeArr = $user_changes;
//        dd('room_data', $room_data);
//        dd('user_chairs', $user_chairs);
//        dd('changeArr', $changeArr);
        foreach ($user_chairs as $k => $v) {
            switch ($v) {
                case 1:
                    $charNo = 4;
                    break;
                case 2:
                    $charNo = 3;
                    break;
                case 3:
                    $charNo = 2;
                    break;
                case 4:
                    $charNo = 1;
                    break;
            }
            $changeCard = [];
            foreach ($user_chairs as $m) {
                if ($m == $charNo) {
                    $changeCard = $changeArr[$m];
                }
            }
            //拿到玩家手牌
            $user_data = json_decode($room_data[$k], true);
//            dd('user_data_befor', $user_data);
//            dd('charNo', $charNo);
//            dd('k', $v);
//            dd('changeCard', $changeCard);
            //去掉选出的换牌
            foreach ($changeArr[$v] as $m) {
                foreach ($user_data['card'] as $n => $p) {
                    if ($m == $p) {
                        unset($user_data['card'][$n]);
                        break;
                    }
                }
            }
            sort($user_data['card']);
            $user_rest_cards = $user_data['card'];
//            dd('user_rest_cards', $user_rest_cards);
            //加入其他玩家的换牌
            $user_cards = array_merge($user_rest_cards, $changeCard);
            sort($user_cards);
            $user_data['card'] = $user_cards;
            //更新房间玩家手牌数据
            $room_data[$k] = $user_data;
//            dd('room_data', $room_data);
        }
//        dd('room_data', $room_data);
        $room_data_key = sprintf($game_conf['user_room_data'], $room_no);
        arrToHashInRedis($room_data, $room_data_key);

        //更新游戏进度为定缺，重置操作计数器
        setGameProgress($room_no, GameProgress::GAME_CHOOSE_COLOR);
        resetOperCounter($room_no);

        //广播换牌结果，每个人收到的都是自己专属的牌组信息
        foreach ($user_chairs as $k => $v) {
            $fd = getFdByAccount($k);
            if ($fd) {
                $returnData = $room_data[$k];
                if (gettype($returnData) == 'string') {
                    $returnData = json_decode($returnData, true);
                }
//                dd('k', $k);
//                dd('returnData', $returnData);
                pushDataToUser($serv, $fd, $returnData, SubCmd::SUB_GAME_CHANGE_OVER_RESP);
            }
        }
        //5秒后广播推送定缺
        delayBroadCast(5, $room_no, ['wait_time' => $user_conf['choose_timer']],
            SubCmd::SUB_GAME_START_CHOOSE_COLOR, self::$CHOOSE_COLOR_TIMER);
    }

    //定缺
    public function do_choose_color($room_no)
    {
        ddTitle('start do_choose_color :' . $room_no);

        //检查游戏进度，如果不是当前进度，则不执行当前调用流程
        if (!checkGameProgress($room_no, GameProgress::GAME_CHOOSE_COLOR)) {
            ddTitle('exit by game progress, current progress: ' . getGameProgress($room_no) . ' need progress:' . GameProgress::GAME_CHOOSE_COLOR);
            return;
        }

        //添加操作计数器，防止重复操作
        addOperCounter($room_no);
        //检查计数器，如果计数器被增加了，表示操作被执行过，则不再重复执行该调用流程
        if (!checkCounter($room_no)) {
            ddTitle('exit by opercounter, current counter: ' . getCounter($room_no));
            return;
        }

        $user_conf = config('user');
        $user_colors = getRoomColors($room_no);
        $user_chairs = getRoomChairs($room_no);

        // 1.判断已操作换牌用户数，没满员则由系统自动给未操作玩家执行换牌
//        dd('user_colors', $user_colors);
        $notOperUserArr = [];
        if (count($user_colors) < 4) {
            $colorKyes = array_keys($user_colors);
            foreach ($user_chairs as $k => $v) {
                if (!in_array($v, $colorKyes)) {
                    $notOperUserArr[] = ['account' => $k, 'chair_id' => $v];
                }
            }
        }
//        dd('notOperUserArr', $notOperUserArr);
        if (!empty($notOperUserArr)) {
//            ddNode('auto choose color, players:' . count($notOperUserArr));
            foreach ($notOperUserArr as $v) {
                $user_colors[$v['chair_id']] = randColor();
            }
        }
//        dd('user_colors', $user_colors);

        $colorData = [];
        foreach ($user_colors as $k => $v) {
            $colorData[] = ['chair_id' => $k, 'que' => $v];
        }

        //更新游戏进度为出牌，重置操作计数器
        setGameProgress($room_no, GameProgress::GAME_OUT_CARD);
        resetOperCounter($room_no);


        delayBroadCast(1, $room_no, ['colors' => $colorData], SubCmd::SUB_GAME_CHOOSE_OVER_RESP);

        $room_data = getRoomData($room_no);
//        dd('room_data', $room_data);
        $master = $room_data['master'];
        updateRoomData($room_no, ['next_chair_id' => $master]);
        //发送出牌消息
        delayBroadCast(5, $room_no, ['next_chair_id' => $master,
            'wait_time' => $user_conf['play_timer']], SubCmd::SUB_GAME_OUT_CARD,
            self::$OUT_CARD_TIMER);
    }

    //出牌
    public function do_out_card($room_no)
    {
        ddTitle('start do_out_card :' . $room_no);

        //检查游戏进度，如果不是当前进度，则不执行当前调用流程
        if (!checkGameProgress($room_no, GameProgress::GAME_OUT_CARD)) {
            ddTitle('exit by game progress, current progress: ' . getGameProgress($room_no) . ' need progress:' . GameProgress::GAME_OUT_CARD);
            return;
        }

        //添加操作计数器，防止重复操作
        addOperCounter($room_no);
        //检查计数器，如果计数器被增加了，表示操作被执行过，则不再重复执行该调用流程
        if (!checkCounter($room_no)) {
            ddTitle('exit by opercounter, current counter: ' . getCounter($room_no));
            return;
        }

        $room_data = getRoomData($room_no);
        $out_cards = isset($room_data['out']) ? json_decode($room_data['out'], true) : [];
        // 1.判断已操作出牌用户数据，用户没出牌则由系统自动给玩家执行出牌
//        dd('out_cards befor', $out_cards);
        if (empty($out_cards)) { //系统自动打出刚摸的牌
            $in_card = isset($room_data['in']) ? json_decode($room_data['in'], true) : [];
            if (empty($in_card)) {
                $masterAccount = getAccountByChairId($room_no, $room_data['master']);
                $masterCards = json_decode($room_data[$masterAccount], true);
                $in_card['card'] = $masterCards['card'][count($masterCards) - 1];
                $in_card['chair_id'] = $room_data['master'];
            }
            $card = $in_card['card'];
            $chair_id = $in_card['chair_id'];
        } else {
            $card = $out_cards['card'];
            $chair_id = $out_cards['chair_id'];
        }
        $out_cards = ['chair_id' => $chair_id, 'card' => $card];
//        dd('out_cards after', $out_cards);

        //本轮次上一次牌型
        $last_chair_id = isset($room_data['last_chair_id']) ? $room_data['last_chair_id'] : $chair_id;
        //下一个出牌人椅子id
        $next_chair_id = $chair_id + 1;
        $next_chair_id = ($next_chair_id > 4) ? $next_chair_id - 4 : $next_chair_id;

        //轮次
        $round = isset($room_data['round']) ? $room_data['round'] + 1 : 0;
        //手次
        $hand_num = isset($room_data['hand_num']) ? $room_data['hand_num'] + 1 : 1;

        $account = getAccountByChairId($room_no, $chair_id);
//        ddTitle("auto out card，account: { $account }  chair_id: { $chair_id } ");
        //设置减少手牌数据
        $param = setMyOutCard($room_no, $out_cards, $account, $round, $hand_num,
            $last_chair_id, $next_chair_id);


//        dd('out card param', $param);
        ddNode('do_out_card end ');
        //更新游戏进度为检查胡碰杠，重置操作计数器，重置检查胡碰杠缓存
        setGameProgress($room_no, GameProgress::GAME_CHECK_HPG);
        resetOperCounter($room_no);
        resetCheckHpg($room_no);

        $out_result = [
            'status' => 0,
            'chair_id' => $chair_id, //出牌椅子
            'card' => $out_cards['card'],        //本次出牌
        ];
        //异步广播出牌消息，并设置检查胡碰杠计时器
        delayBroadCast(1, $room_no, $out_result, SubCmd::SUB_GAME_OUT_CARD_RESP, GameTimer::$CHECK_HPK_TIMER);
    }

    //检查胡碰杠
    public function do_check_hpk($room_no)
    {
        ddTitle('start do_check_hpk :' . $room_no);
        //检查游戏进度，如果不是当前进度，则不执行当前调用流程
        if (!checkGameProgress($room_no, GameProgress::GAME_CHECK_HPG)) {
            ddTitle('exit by game progress, current progress: ' . getGameProgress($room_no) . ' need progress:' . GameProgress::GAME_CHECK_HPG);
            return;
        }

        //添加操作计数器，防止重复操作
        addOperCounter($room_no);
        //检查计数器，如果计数器被增加了，表示操作被执行过，则不再重复执行该调用流程
        if (!checkCounter($room_no)) {
            ddTitle('exit by opercounter, current counter: ' . getCounter($room_no));
            return;
        }

        $user_conf = config('user');
        $serv = server();
        $user_checks = getCheckHPG($room_no);

        $room_data = getRoomData($room_no);

        $out_cards = json_decode($room_data['out'], true);

//        dd('out_cards', $out_cards);

        if (empty($out_cards)) {
            dd('数据错误，没有出牌信息，请重置游戏');
            //TODO 发送错误提示重置游戏
            return;
        }

        $user_chairs = getRoomChairs($room_no);

        $out_card_account = getAccountByChairId($room_no, $out_cards['chair_id']);

        // 1.判断已操作检查胡碰杠用户数，没满员则由系统自动给未操作玩家执行过牌
//        dd('user_checks', $user_checks);
        $notOperUserArr = [];
        if (count($user_checks) < 3) {
            foreach ($user_chairs as $k => $v) {
                if ($k != $out_card_account) {
                    if (!isset($user_checks[$k])) {
                        $notOperUserArr[$k] = 0;
                    }
                }
            }
        }
//        dd('notOperUserArr', $notOperUserArr);
        if (!empty($notOperUserArr)) {
//            ddNode('auto checkhpg, players:' . count($notOperUserArr));
            foreach ($notOperUserArr as $k => $v) {
                $user_checks[$k] = 0; //默认过牌
            }
        }
//        dd('user_checks', $user_checks);

        $flag = false;

        foreach ($user_checks as $account => $v) {
            if ($v == 1) { //胡牌
                ddNode('d-1');
                $chair_id = findChairId($room_no, $account); // 座位号
                $res = checkHu($room_no, $out_cards['card'], $account);
//                dd('account', $account);
//                dd('hu-res', $res);
                if ($res['status']) {
//                    pushErr($serv, $fd, $scmd, $res['info']);
                    $flag = true;
                    break;
                }
                //广播胡牌
                delayBroadCast(1, $room_no, $res['data'], SubCmd::SUB_GAME_HU_CARD_RESP);

                //广播发牌消息
                $next_account = getAccountByChairId($room_no, $res['data']['next_chair_id']);
                $res = sendCard($room_no, $next_account);
//                dd('sendCard-res', $res);
                if ($res['status']) {
//                    pushErr($serv, $fd, $scmd, $res['info']);
                    $flag = true;
                    break;
                }
                $flag = false;
                //更新游戏进度为出牌，重置操作计数器
                setGameProgress($room_no, GameProgress::GAME_OUT_CARD);
                resetOperCounter($room_no);
                ddNode('do_check_hpk end d-1');
                //给自己发送通知，包含所摸牌的信息,给其他人发送通知，不含所摸牌的信息
                \Swoole\Timer::after(1, function () use ($room_no, $serv, $res, $next_account) {
                    $fds = getOtherFdsByRoomNo($room_no);// 房间玩家链接
                    $fd = getFdByAccount($next_account);
                    foreach ($fds as $fdv) {
                        if ($fdv == $fd) {
                            pushDataToUser($serv, $fdv, ['card' => $res['data']['card'], 'chair_id' => $res['data']['next_chair_id'], 'hand_num' => $res['data']['hand_num']], SubCmd::SUB_GAME_SEND_CARD);
                        } else {
                            pushDataToUser($serv, $fdv, ['chair_id' => $res['data']['next_chair_id'], 'hand_num' =>
                                $res['data']['hand_num']], SubCmd::SUB_GAME_SEND_CARD);
                        }
                    }
                });
                //广播出牌消息
                delayBroadCast(1, $room_no, ['next_chair_id' => $res['data']['next_chair_id'],
                    'wait_time' => $user_conf['play_timer']], SubCmd::SUB_GAME_OUT_CARD,
                    self::$OUT_CARD_TIMER);
            } else {
                $flag = true;
            }
        }
        if ($flag) {
            foreach ($user_checks as $account => $v) {
                if ($v == 2) { //杠牌
                    ddNode('d-2');
                    $res = checkGang($room_data, $out_cards['card'], $account);
//                    dd('account', $account);
                    dd('gang-res', $res);
                    if ($res['status']) {
//                        pushErr($serv, $fd, $scmd, $res['info']);
                        $flag = true;
                        break;
                    }

                    //更新游戏进度为出牌，重置操作计数器
                    setGameProgress($room_no, GameProgress::GAME_OUT_CARD);
                    resetOperCounter($room_no);

                    //广播杠牌通知
                    delayBroadCast(1, $room_no, ['card' => $out_cards['card'],
                        'chair_id' => $res['data']['chair_id'], 'from_chair_id' => $res['data']['from_chair_id']],
                        SubCmd::SUB_GAME_GANG_CARD_RESP);

                    //广播发牌消息
                    $next_account = $account;
                    $res = sendCard($room_no, $next_account);
//                    dd('sendCard-res', $res);
                    if ($res['status']) {
//                        pushErr($serv, $fd, $scmd, $res['info']);
                        $flag = true;
                        break;
                    }
                    $flag = false;
                    ddNode('do_check_hpk end d-2');
                    //给自己发送通知，包含所摸牌的信息,给其他人发送通知，不含所摸牌的信息
                    \Swoole\Timer::after(3, function () use (
                        $room_no, $serv, $res,
                        $next_account
                    ) {
                        $fds = getOtherFdsByRoomNo($room_no);// 房间玩家链接
                        $fd = getFdByAccount($next_account);
                        foreach ($fds as $fdv) {
//                            dd('send card', $fdv);
                            if ($fdv == $fd) {
                                pushDataToUser($serv, $fdv, ['card' => $res['data']['card'], 'chair_id' => $res['data']['chair_id'], 'hand_num' => $res['data']['hand_num']], SubCmd::SUB_GAME_SEND_CARD);
                            } else {
                                pushDataToUser($serv, $fdv, ['chair_id' => $res['data']['chair_id'], 'hand_num' =>
                                    $res['data']['hand_num']], SubCmd::SUB_GAME_SEND_CARD);
                            }
                        }
                    });
                    //广播出牌消息
                    delayBroadCast(4, $room_no, ['next_chair_id' => $res['data']['chair_id'],
                        'wait_time' => $user_conf['play_timer']], SubCmd::SUB_GAME_OUT_CARD,
                        self::$OUT_CARD_TIMER);
                } else {
                    $flag = true;
                }
            }
        }
        if ($flag) {
            foreach ($user_checks as $account => $v) {
                if ($v == 3) { //碰牌
                    ddNode('d-3');
                    $res = checkPeng($room_data, $out_cards['card'], $account);
//                    dd('account', $account);
                    dd('peng-res', $res);
                    if ($res['status']) {
//                        pushErr($serv, $fd, $scmd, $res['info']);
                        $flag = true;
                        break;
                    }
                    $flag = false;
                    ddNode('do_check_hpk end d-3');
                    //更新游戏进度为出牌，重置操作计数器
                    setGameProgress($room_no, GameProgress::GAME_OUT_CARD);
                    resetOperCounter($room_no);
                    //广播碰牌的信息
                    delayBroadCast(1, $room_no, ['status' => 0, 'card' => $out_cards['card'],
                        'chair_id' => $res['data']['chair_id'], 'from_chair_id' => $res['data']['from_chair_id']],
                        SubCmd::SUB_GAME_PENG_OVER_RESP);

                    //广播出牌消息
                    delayBroadCast(3, $room_no, ['next_chair_id' => $res['data']['chair_id'],
                        'wait_time' => $user_conf['play_timer']], SubCmd::SUB_GAME_OUT_CARD,
                        self::$OUT_CARD_TIMER);
                } else {
                    $flag = true;
                }
            }
        }
        if ($flag) {
            ddNode('d-4');
            //下一个出牌人椅子id
            $next_chair_id = $room_data['next_chair_id']; // 座位号
            //广播发牌消息
            $next_account = getAccountByChairId($room_no, $next_chair_id);
            $res = sendCard($room_no, $next_account);
//            dd('account', $account);
            dd('sendCard-res', $res);
            if ($res['status']) {
                return;
            }
            ddNode('do_check_hpk end d-4');
            //更新游戏进度为出牌，重置操作计数器
            setGameProgress($room_no, GameProgress::GAME_OUT_CARD);
            resetOperCounter($room_no);

            //给自己发送通知，包含所摸牌的信息,给其他人发送通知，不含所摸牌的信息
//            \Swoole\Timer::after(1, function () use ($room_no, $serv, $res, $next_account) {
            $fds = getOtherFdsByRoomNo($room_no);// 房间玩家链接
            $fd = getFdByAccount($next_account);
            foreach ($fds as $fdv) {
//                    dd('send card', $fdv);
                if ($fdv == $fd) {
                    pushDataToUser($serv, $fdv, ['card' => $res['data']['card'], 'chair_id' => $res['data']['chair_id'], 'hand_num' => $res['data']['hand_num']], SubCmd::SUB_GAME_SEND_CARD);
                } else {
                    pushDataToUser($serv, $fdv, ['chair_id' => $res['data']['chair_id'], 'hand_num' =>
                        $res['data']['hand_num']], SubCmd::SUB_GAME_SEND_CARD);
                }
            }
//            });

            //广播出牌消息
            delayBroadCast(2, $room_no, ['next_chair_id' => (int)$next_chair_id,
                'wait_time' => $user_conf['play_timer']], SubCmd::SUB_GAME_OUT_CARD,
                self::$OUT_CARD_TIMER);
        }
    }
}